package com.xbongbong.paas.connection.connector.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.connection.enums.OpenAppEnum;
import com.xbongbong.paas.connection.pojo.connector.AmountAllocationPojo;
import com.xbongbong.paas.connection.pojo.connector.CustomerStandardFormatPojo;
import com.xbongbong.paas.connection.pojo.connector.DdCustomerStandardActionPojo;
import com.xbongbong.paas.connection.pojo.connector.DdReimbursementStandardActionPojo;
import com.xbongbong.paas.connection.pojo.connector.ExpenseAmountPojo;
import com.xbongbong.paas.connection.pojo.connector.ExpenseDetailPojo;
import com.xbongbong.paas.connection.pojo.connector.InvoiceTitlePojo;
import com.xbongbong.paas.connection.pojo.connector.ReimbursementAmountPojo;
import com.xbongbong.paas.connection.pojo.connector.ReimbursementStandardFormatPojo;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.pro.enums.errorcodes.ApprovalErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ext.ExpenseEntityExt;
import com.xbongbong.saas.domain.entity.ext.ReimbursementFormEntityExt;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.ExpenseEnum;
import com.xbongbong.saas.enums.business.ReimbursementFormEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.model.ExpenseModel;
import com.xbongbong.saas.model.ReimbursementFormModel;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.UserModel;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;

@Service("reimbursementStandardConnector")
public class ReimbursementStandardConnector extends AbstractStandardConnector {

    private static final Logger LOG = LoggerFactory.getLogger(ReimbursementStandardConnector.class);

    @Resource
    private EsHelper esHelper;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private UserModel userModel;
    @Resource
    private ReimbursementFormModel reimbursementFormModel;
    @Resource
    private ExpenseModel expenseModel;

    @Override
    protected PaasFormDataEntityExt getEntity(String corpid, JSONObject jsonObject) throws XbbException {
        DdReimbursementStandardActionPojo ddReimbursementStandardActionPojo = jsonObject.toJavaObject(DdReimbursementStandardActionPojo.class);
        ReimbursementStandardFormatPojo data = ddReimbursementStandardActionPojo.getData();
        String serialNo = data.getCode();
//        PaasFormDataEntityExt reimbursement = reimbursementFormModel.getByFormDataCode(corpid, serialNo);
        PaasFormDataEntityExt reimbursement = getReimbursementBySerialNo(corpid, serialNo);
        return reimbursement;
    }

    @Override
    protected void addStandard(String corpid, UserVO userVo, JSONObject jsonObject) throws XbbException {
        DdReimbursementStandardActionPojo ddReimbursementStandardActionPojo = jsonObject.toJavaObject(DdReimbursementStandardActionPojo.class);
        ReimbursementStandardFormatPojo data = ddReimbursementStandardActionPojo.getData();
        ReimbursementFormEntityExt reimbursementFormEntityExt = reimbursementFormat(corpid, data);
        List<ExpenseEntityExt> expenseEntityList = reimbursementFormEntityExt.getExpenseList();
        try {
            reimbursementFormModel.insert(reimbursementFormEntityExt);
            for (ExpenseEntityExt expenseEntity : expenseEntityList) {
                JSONObject expenseData = expenseEntity.getData();
                expenseData.put(ExpenseEnum.REIMBURSEMENT_FORM_ID.getAttr(), reimbursementFormEntityExt.getId());
                expenseEntity.setData(expenseData);
            }
            expenseModel.insertBatch(expenseEntityList);
        } catch (Exception e) {
            LOG.error("mkDataAdd 数据保存失败，" + e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    private ReimbursementFormEntityExt reimbursementFormat(String corpid, ReimbursementStandardFormatPojo data) throws XbbException {
        PaasFormEntityExt reimbursementFormPaasForm = paasFormModel.getByBusinessType(XbbRefTypeEnum.REIMBURSEMENT_FORM.getCode(), corpid);
        PaasFormEntityExt expensePaasForm = paasFormModel.getByBusinessType(XbbRefTypeEnum.EXPENSE.getCode(), corpid);

        if (Objects.isNull(reimbursementFormPaasForm) || Objects.isNull(expensePaasForm)) {
            throw new XbbException(ApprovalErrorCodeEnum.API_ERROR_209012);
        }

        Long reimbursementFormMenuId = reimbursementFormPaasForm.getMenuId();
        Long reimbursementFormAppId = reimbursementFormPaasForm.getAppId();
        Long reimbursementFormFormId = reimbursementFormPaasForm.getId();
        Long expenseMenuId = expensePaasForm.getMenuId();
        Long expenseAppId = expensePaasForm.getAppId();
        Long expenseFormId = expensePaasForm.getId();

        Long now = DateTimeUtil.getInt();
        ReimbursementFormEntityExt reimbursementFormEntityExt = dataReimbursementFormat(corpid, data);

        String formDataCode = data.getCode();
        //之前是每刻报销传过来的是formUserCode
        String formUserCode = data.getApplicantEmployeeId();
        String formUserName = null;
        if (StringUtil.isEmpty(formUserName)) {
            UserEntity user = userModel.getByKey(formUserCode, corpid);
            formUserName = Objects.isNull(user) ? "" : user.getName();
        }
        //之前每刻报销传过来的是departmentCode
        Long departmentCode = Long.parseLong(data.getDepartmentCode());

        reimbursementFormEntityExt.setCorpid(corpid);
        reimbursementFormEntityExt.setAppId(reimbursementFormAppId);
        reimbursementFormEntityExt.setMenuId(reimbursementFormMenuId);
        reimbursementFormEntityExt.setFormId(reimbursementFormFormId);
        reimbursementFormEntityExt.setSerialNo(formDataCode);
        reimbursementFormEntityExt.setAddTime(now);
        reimbursementFormEntityExt.setUpdateTime(now);
        reimbursementFormEntityExt.setDel(BasicConstant.ZERO);

        List<ExpenseEntityExt> expenseEntityList = new ArrayList<>();

        List<ExpenseDetailPojo> expenseDetails = data.getExpenseDetails();
        Set<String> referenceTypeSet = new HashSet<>();
        for (ExpenseDetailPojo expense : expenseDetails) {
            String expenseCode = expense.getDetailCode();
            String expenseType = expense.getType();
            String consumeCity = expense.getConsumeCity();
            Long consumeTime = expense.getConsumeAt() / 1000L;

            Double expenseAmount = null;
            ExpenseAmountPojo expenseAmountPojo = expense.getAmount();
            if (Objects.nonNull(expenseAmountPojo)) {
                String amountStr = expenseAmountPojo.getAmountStr();
                expenseAmount = StringUtil.toDouble(amountStr, 0D);
            }
            List<AmountAllocationPojo> amountAllocations = expense.getAmountAllocations();
            for (AmountAllocationPojo allocation : amountAllocations) {
                String projectCode = allocation.getProjectCode();
                String projectName = allocation.getProjectName();
                String type = allocation.getBusinessCode();

                ExpenseAmountPojo allocationAmount = allocation.getAmount();
                Double apportionedAmount = null;
                if (Objects.nonNull(allocationAmount)) {
                    String amountStr = allocationAmount.getAmountStr();
                    apportionedAmount = StringUtil.toDouble(amountStr, 0D);
                }
                ExpenseEntityExt expenseEntityExt = new ExpenseEntityExt();
                expenseEntityExt.setCorpid(corpid);
                expenseEntityExt.setAppId(expenseAppId);
                expenseEntityExt.setMenuId(expenseMenuId);
                expenseEntityExt.setFormId(expenseFormId);
                expenseEntityExt.setSerialNo(expenseCode);
                expenseEntityExt.setOwnerId(formUserCode);
                expenseEntityExt.setDepartmentId(departmentCode);
                expenseEntityExt.setFlowStatus(FlowStatusEnum.NOT_NEED_APPROVAL.getType());
                expenseEntityExt.setCreatorId(formUserCode);
                expenseEntityExt.setAddTime(now);
                expenseEntityExt.setUpdateTime(now);
                expenseEntityExt.setDel(BasicConstant.ZERO);
                JSONObject expenseData = new JSONObject();
                expenseData.put(ExpenseEnum.OPEN_APP_ID.getAttr(), OpenAppEnum.MEI_KE_BAO_XIAO.getOpenAppId());
                expenseData.put(ExpenseEnum.LINK_REIMBURSEMENT_FORM_HIDE.getAttr(), formDataCode);
                expenseData.put(ExpenseEnum.EXPENSE_TYPE.getAttr(), expenseType);
                expenseData.put(ExpenseEnum.CONSUME_CITY.getAttr(), consumeCity);
                expenseData.put(ExpenseEnum.AMOUNT.getAttr(), expenseAmount);
                expenseData.put(ExpenseEnum.CONSUME_TIME.getAttr(), consumeTime);
                expenseData.put(ExpenseEnum.FORM_USER_CODE.getAttr(), formUserCode);
                expenseData.put(ExpenseEnum.FORM_USER_NAME.getAttr(), formUserName);

                projectName = setBusinessInfo(corpid, expenseData, type, projectCode);

                expenseData.put(ExpenseEnum.PROJECT_NAME.getAttr(), projectName);
                expenseData.put(ExpenseEnum.PROJECT_CODE.getAttr(), projectCode);
                expenseData.put(ExpenseEnum.APPORTIONED_AMOUNT.getAttr(), apportionedAmount);
                referenceTypeSet.add(type);
                expenseEntityExt.setData(expenseData);
                expenseEntityList.add(expenseEntityExt);
            }
        }
        JSONObject reimbursementFormData = reimbursementFormEntityExt.getData();
        reimbursementFormData.put(ReimbursementFormEnum.REFERENCE_TYPE.getAttr(), JSON.toJSONString(referenceTypeSet));
        reimbursementFormEntityExt.setData(reimbursementFormData);
        reimbursementFormEntityExt.setExpenseList(expenseEntityList);
        return reimbursementFormEntityExt;
    }



    /**
     * 设置销帮帮关联业务
     * @param corpid
     * @param expenseData 费用data
     * @param type  业务类型，CUSTOMER,CONTRACT,OPPORTUNITY
     * @param serialNo 客户/机会/合同编码
     * 创建时间 2020/3/31 3:53 PM
     * 修改时间 2020/3/31 3:53 PM
     * @author chy
     */
    private String setBusinessInfo(String corpid, JSONObject expenseData, String type, String serialNo) throws XbbException {
        if (StringUtil.isEmpty(type)) {
            return "";
        }

        String projectName = "";

        switch (type) {
            case "CUSTOMER":
                PaasFormDataEntityExt customer = getCustomerBySerialNo(corpid, serialNo);
                if (Objects.isNull(customer)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404);
                }
                expenseData.put(ExpenseEnum.CUSTOMER_ID.getAttr(), customer.getDataId());
                projectName = customer.getData().getString(CustomerManagementEnum.NAME.getAttr());
                expenseData.put(ExpenseEnum.LINK_CUSTOMER_ID_HIDE.getAttr(), projectName);
                break;
            case "OPPORTUNITY":
                PaasFormDataEntityExt opportunity = getOpportunityBySerialNo(corpid, serialNo);
                if (Objects.isNull(opportunity)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404);
                }
                expenseData.put(ExpenseEnum.OPPORTUNITY_ID.getAttr(), opportunity.getDataId());
                projectName = opportunity.getData().getString(SalesOpportunityEnum.NAME.getAttr());
                expenseData.put(ExpenseEnum.LINK_OPPORTUNITY_ID_HIDE.getAttr(), projectName);
                break;
            case "CONTRACT":
                PaasFormDataEntityExt contract = getContractBySerialNo(corpid, serialNo);
                if (Objects.isNull(contract)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404);
                }
                expenseData.put(ExpenseEnum.CONTRACT_ID.getAttr(), contract.getDataId());
                projectName = contract.getData().getString(ContractEnum.NAME.getAttr());
                expenseData.put(ExpenseEnum.LINK_CONTRACT_ID_HIDE.getAttr(), projectName);
                break;
            default:
                break;
        }
        return projectName;
    }

    /**
     * 报销单主题数据格式化
     * @param corpid
     * @param data
     * @return
     */
    private ReimbursementFormEntityExt dataReimbursementFormat(String corpid, ReimbursementStandardFormatPojo data) {
        String formType = "REIMBURSE";
        String formSubType = "普通报销";
        //事由，使用单据标题
        String formName = data.getTitle();
        //之前是每刻报销传过来的是formUserCode
        String formUserCode = data.getApplicantEmployeeId();
        String formUserName = null;
        if (StringUtil.isEmpty(formUserName)) {
            UserEntity user = userModel.getByKey(formUserCode, corpid);
            formUserName = Objects.isNull(user) ? "" : user.getName();
        }
        Long departmentCode = Long.parseLong(data.getDepartmentCode());
        //报销金额
        Double approvedAmount = null;
        ReimbursementAmountPojo amount = data.getAmount();
        if ( Objects.nonNull(amount)) {
            String amountStr = amount.getAmountStr();
            approvedAmount = StringUtil.toDouble(amountStr, 0D);
        }
        //提单时间使用现在的创建时间
        Long createAt = data.getCreateAt();
        Long submitTime = null;
        if (Objects.nonNull(createAt)) {
            submitTime = createAt/1000L;
        }
        //公司抬头，原字段entLegalName
        String entLegalName = null;
        InvoiceTitlePojo invoiceTitle = data.getInvoiceTitle();
        if (Objects.nonNull(invoiceTitle)) {
            entLegalName = invoiceTitle.getInvoiceTitleName();
        }
        ReimbursementFormEntityExt reimbursementFormEntityExt = new ReimbursementFormEntityExt();
        reimbursementFormEntityExt.setOwnerId(formUserCode);
        reimbursementFormEntityExt.setDepartmentId(departmentCode);
        //TODO 审批状态怎么处理
        reimbursementFormEntityExt.setFlowStatus(FlowStatusEnum.NOT_NEED_APPROVAL.getType());
        reimbursementFormEntityExt.setCreatorId(formUserCode);
        JSONObject reimbursementFormData = new JSONObject();
        reimbursementFormData.put(ReimbursementFormEnum.OPEN_APP_ID.getAttr(), OpenAppEnum.MEI_KE_BAO_XIAO.getOpenAppId());
        reimbursementFormData.put(ReimbursementFormEnum.FORM_TYPE.getAttr(), formType);
        reimbursementFormData.put(ReimbursementFormEnum.FORM_SUB_TYPE.getAttr(), formSubType);
        reimbursementFormData.put(ReimbursementFormEnum.FORM_NAME.getAttr(), formName);
        reimbursementFormData.put(ReimbursementFormEnum.FORM_USER_CODE.getAttr(), formUserCode);
        reimbursementFormData.put(ReimbursementFormEnum.FORM_USER_NAME.getAttr(), formUserName);
        reimbursementFormData.put(ReimbursementFormEnum.APPROVED_AMOUNT.getAttr(), approvedAmount);
        reimbursementFormData.put(ReimbursementFormEnum.ENT_LEGAL_NAME.getAttr(), entLegalName);
        reimbursementFormData.put(ReimbursementFormEnum.SUBMIT_TIME.getAttr(), submitTime);
        reimbursementFormEntityExt.setData(reimbursementFormData);
        return reimbursementFormEntityExt;
    }

    @Override
    protected void updateStandard(String corpid, UserVO userVo, JSONObject jsonObject, PaasFormDataEntityExt paasFormData) throws XbbException {
        JSONObject dbData = paasFormData.getData();
        dbData.putAll(jsonObject);
        paasFormData.setData(dbData);
        //每刻那边只会更新报销单信息
        paasFormData.setUpdateTime(DateTimeUtil.getInt());
        reimbursementFormModel.update((ReimbursementFormEntityExt)paasFormData);
    }

    @Override
    protected void deleteCore(UserVO userVo, JSONObject jsonObject) throws XbbException {
        String corpid = userVo.getCorpid();
        DdCustomerStandardActionPojo ddCustomerStandardActionPojo = JSONObject.toJavaObject(jsonObject, DdCustomerStandardActionPojo.class);
        CustomerStandardFormatPojo data = ddCustomerStandardActionPojo.getData();
        Long ddDataGmtModified = ddCustomerStandardActionPojo.getDdDataGmtModified();
        Long modifiedTime = ddDataGmtModified/1000L;
        String serialNo = data.getCode();
        ReimbursementFormEntityExt reimbursementForm = reimbursementFormModel.getByFormDataCode(corpid, serialNo);
        if (Objects.isNull(reimbursementForm)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
        }

        if (reimbursementForm.getUpdateTime() >= modifiedTime) {
            LOG.info("存在报销单，但报销单的更新时间>=执行动作接收到的更新时间 id:" + reimbursementForm.getId());
        }
        LOG.info("reimbursementForm not null");
        //获取报销单下所有的费用记录
        List<Long> expenseIdList = getExpenseIdByReimbursementFormCode(corpid, reimbursementForm.getDataId());
        LOG.info("expenseIdList.size:" + expenseIdList.size());
        if (!expenseIdList.isEmpty()) {
            LOG.info("expenseIdList not null");
            //删除报销单下的所有费用
            expenseModel.deleteBatch(expenseIdList, corpid);
            //删除报销单
            reimbursementFormModel.deleteByKey(reimbursementForm.getId(), corpid);
        }
    }

    private PaasFormDataEntityExt getReimbursementBySerialNo(String corpid, String serialNo) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery(BasicConstant.SERIAL_NO + ".keyword", serialNo));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        List<String> fieldList = new ArrayList<>();
        fieldList.add(StringConstant.DATA_ID);
        fieldList.add(StringConstant.CORPID);
        fieldList.add("serialNo");
        fieldList.add("appId");
        fieldList.add("menuId");
        fieldList.add("formId");
        fieldList.add("updateTime");
        List<PaasFormDataEntityExt> paasFormDataEntityExtList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_REIMBURSEMENT_FORM,boolQueryBuilder,PaasFormDataEntityExt.class,fieldList);
        LOG.info("paasFormDataEntityExtList:" + paasFormDataEntityExtList.size());
        return paasFormDataEntityExtList.isEmpty() ? null : paasFormDataEntityExtList.get(0);
    }


    /**
     * 获取报销单下费用的id集合
     * @param corpid 公司id
     * @param reimbursementFormId 报销单编号
     * @return
     * @throws XbbException
     * 创建时间 2020/3/16 6:33 PM
     * 修改时间 2020/3/16 6:33 PM
     * @author chy
     */
    private List<Long> getExpenseIdByReimbursementFormCode(String corpid, Long reimbursementFormId) throws XbbException {
        String esData = StringConstant.JSON_DATA + StringConstant.POINT;
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery(esData + ExpenseEnum.REIMBURSEMENT_FORM_ID.getAttr(), reimbursementFormId));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        List<String> fieldList = new ArrayList<>();
        fieldList.add(StringConstant.DATA_ID);
//        fieldList.add(StringConstant.JSON_DATA);
        List<PaasFormDataEntityExt> paasFormDataEntityExtList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_EXPENSE,boolQueryBuilder,PaasFormDataEntityExt.class,fieldList);
        List<Long> expenseIdList = new ArrayList<>();
        for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExtList) {
            expenseIdList.add(paasFormDataEntityExt.getDataId());
        }
        return expenseIdList;
    }
}
